using System;

namespace PropertyExpression.Common
{
    public interface IChoice<out T1, out T2>
    {
        T Match<T>(Func<T1, T> choice1, Func<T2, T> choice2);
    }

    public static class Choice
    {
        public static IChoice<T1, T2> Choice1<T1, T2>(this T1 choice1, Type<T2> choice2)
        {
            return new Choice1Impl<T1, T2>(choice1);
        }

        public static IChoice<T1, T2> Choice2<T1, T2>(this T2 choice2, Type<T1> choice1)
        {
            return new Choice2Impl<T1, T2>(choice2);
        }

        public static bool IsChoice1<T1, T2>(this IChoice<T1, T2> it)
        {
            return it.Match(_ => true, _ => false);
        }

        public static bool IsChoice2<T1, T2>(this IChoice<T1, T2> it)
        {
            return it.Match(_ => false, _ => true);
        }

        public static void Match<T1, T2>(this IChoice<T1, T2> it, Action<T1> choice1, Action<T2> choice2)
        {
            it.Match(
                _ =>
                    {
                        choice1(_);
                        return new {};
                    },
                _ =>
                    {
                        choice2(_);
                        return new {};
                    });
        }


        private class Choice1Impl<T1, T2> : IChoice<T1, T2>
        {
            private readonly T1 value;

            public Choice1Impl(T1 value)
            {
                this.value = value;
            }

            public T Match<T>(Func<T1, T> choice1, Func<T2, T> choice2)
            {
                return choice1(value);
            }
        }

        internal class Choice2Impl<T1, T2> : IChoice<T1, T2>
        {
            private readonly T2 value;

            public Choice2Impl(T2 value)
            {
                this.value = value;
            }

            public T Match<T>(Func<T1, T> choice1, Func<T2, T> choice2)
            {
                return choice2(value);
            }
        }
    }
}